package com.king.juc.threads;

import lombok.extern.slf4j.Slf4j;

/**
 * Thread API
 *
 * @author king
 * @date 2020/9/9 13:52
 */
@Slf4j(topic = "c.ThreadApiDemo")
public class ThreadApiDemo {
    private static final Object LOCK = new Object();
    private static int r1 = 0;
    private static int r2 = 0;

    private static final Object room = new Object();
    /**
     * 有没有烟
     */
    private static boolean hasCigarette = false;
    private static boolean hasTakeout = false;

    public static void main(String[] args) throws InterruptedException {

//        run();
//        getState();
//        sleepDemo();
//        interrupt();
//        yield();
//        join();
//        join2();
//        join3();
//        setDaemon();
//        waitAndNotify();
//        WaitAndNotifyDemo();
        WaitAndNotifyDemo2();
    }

    /**
     * Thread.run()
     * 由当前线程执行 run 方法, 而不是 t1
     */
    public static void run() {
        Thread t1 = new Thread(() -> {
            log.debug("running.....");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 直接调用会由当前线程去执行而不是 t1
        t1.run();
//        t1.start();

        log.debug("Main Thread......");
    }

    /**
     * Thread.getState()
     * 线程状态
     * 新建状态为: NEW
     * 启动状态为: RUNNABLE
     */
    public static void getState() {
        Thread t1 = new Thread(() -> log.debug("running....."));

        System.out.println(t1.getState());
        t1.start();
        System.out.println(t1.getState());

    }

    /**
     * Thread.sleep()
     * 睡眠
     *
     * @throws InterruptedException 睡眠被打断抛出异常
     */
    public static void sleepDemo() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println("sleep start.....");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("sleep end.....");
        });
        t1.start();

        Thread.sleep(500);
        log.debug("t1 status {}", t1.getState());
    }

    /**
     * Thread.interrupt()
     * 唤醒休眠
     *
     * @throws InterruptedException sleep中断
     */
    public static void interrupt() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                log.debug("enter sleep~~~~~~~~");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                log.debug("wake up~~~~~~~~~");
                e.printStackTrace();
            }
        }, "t1");
        t1.start();

        Thread.sleep(1000);
        log.debug("interrupt~~~~~~~~~~");
        t1.interrupt();
    }

    /**
     * Thread.yield()
     * 放弃对处理器的当前使用
     */
    public static void yield() {
        Runnable task1 = () -> {
            int count = 0;
            for (; ; ) {
                System.out.println("----->1 " + count++);
            }
        };

        Runnable task2 = () -> {
            int count = 0;
            for (; ; ) {
                // 给调度程序的提示是当前线程愿意放弃对处理器的当前使用。调度程序可以随意忽略此提示。
//                Thread.yield();
                System.out.println("        ------->2 " + count++);
            }
        };

        Thread t1 = new Thread(task1, "t1");
        Thread t2 = new Thread(task2, "t2");

        // 设置线程优先级
        t1.setPriority(Thread.MIN_PRIORITY);
        t2.setPriority(Thread.MAX_PRIORITY);

        t1.start();
        t2.start();
    }

    /**
     * Thread.join()
     * 等待线程结束
     */
    public static void join() {
        log.debug("start");
        Thread t1 = new Thread(() -> {
            log.debug("t1 start");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            r1 = 10;
            log.debug("t1 end");
        }, "t1");

        t1.start();
        try {
            // 等待线程结束
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("r = {}", r1);
        log.debug("end");
    }

    public static void join2() {
        log.debug("start");
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            r1 = 10;
        }, "t1");
        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            r2 = 20;
        }, "t2");

        long start = System.currentTimeMillis();
        t1.start();
        t2.start();
        log.debug("join begin");

        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("t1 join end");

        try {
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("t2 join end");

        long end = System.currentTimeMillis();
        log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
    }

    /**
     * Thread.join(long milis)
     * 有效期等待
     */
    public static void join3() {
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            r1 = 10;
        }, "t1");

        long start = System.currentTimeMillis();
        t1.start();

        // 线程执行结束会导致join结束
        log.debug("join begin");
        try {
            // 达到最大时间则不再等待
//            t1.join(1500);
            // 线程运行结束, 未到达最大时间, 提前结束
            t1.join(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        log.debug("r1: {} cost: {}", r1, end - start);
    }

    /**
     * Thread.isInterrupted()
     * 打断标记
     *
     * @throws InterruptedException
     */
    public static void isInterrupted() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("sleep...");
            ;
            try {
                // wait join sleep等被打断则抛异常, 打断标记位 false
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1");

        t1.start();
        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
        log.debug("打断标记:{}", t1.isInterrupted());
    }

    /**
     * Thread.isInterrupted()
     * 打断标记
     *
     * @throws InterruptedException
     */
    public static void isInterrupted2() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {
                boolean interrupted = Thread.currentThread().isInterrupted();
                // 打断不代表马上停止当前线程, 停止状态由当前线程自己决定
                if (interrupted) {
                    log.debug("状态被打断, 退出循环....");
                    break;
                }
            }
        }, "t1");

        t1.start();
        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
    }

    public static void setDaemon() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
            }
            log.debug("结束");
        }, "t1");

        // 设置守护线程
        t1.setDaemon(true);
        t1.start();

        Thread.sleep(1000);
        log.debug("结束");
    }

    /**
     * wait() notify() notifyAll()
     */
    public static void waitAndNotify() {
        new Thread(() -> {
            synchronized (LOCK) {
                log.debug("执行...");
                try {
                    // 线程等待
//                    LOCK.wait();
                    LOCK.wait(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.debug("其他代码....");
            }
        }, "t1").start();

//        new Thread(() -> {
//            synchronized (LOCK){
//                log.debug("执行....");
//                try {
//                    LOCK.wait();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                log.debug("其他代码....");
//            }
//        }, "t2").start();

        try {
//            Thread.sleep(2000);
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("唤醒 LOCK 上其他线程");

        synchronized (LOCK) {
            // 唤醒上个线程
            LOCK.notify();
            // 唤醒全部线程
//            LOCK.notifyAll();
        }
    }

    /**
     * wait和notify案例1
     *
     * @throws InterruptedException
     */
    public static void WaitAndNotifyDemo() throws InterruptedException {
        new Thread(() -> {
            synchronized (room) {
                log.debug("有烟没? [{}]", hasCigarette);
                if (!hasCigarette) {
                    log.debug("没烟, 先歇会!");
                    try {
//                        Thread.sleep(2000);
                        room.wait(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("有烟没? [{}]", hasCigarette);
                if (hasCigarette) {
                    log.debug("可以开始干活了");
                }
            }
        }, "小南").start();

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                synchronized (room) {
                    log.debug("可以开始干活了");
                }
            }, "其他人").start();
        }

        Thread.sleep(1000);
        new Thread(() -> {
            synchronized (room) {
                hasCigarette = true;
                log.debug("烟送到了");
                room.notify();
            }
        }, "送烟的").start();
    }

    /**
     * wait和notify案例2
     *
     * @throws InterruptedException
     */
    public static void WaitAndNotifyDemo2() throws InterruptedException {

        new Thread(() -> {
            synchronized (room) {
                log.debug("有烟没? [{}]", hasCigarette);
                while (!hasCigarette) {
                    log.debug("没烟, 先歇会!");
                    try {
                        room.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("有烟没? [{}]", hasCigarette);
                if (hasCigarette) {
                    log.debug("可以开始干活了");
                } else {
                    log.debug("没干成活....");
                }
            }
        }, "小南").start();

        new Thread(() -> {
            synchronized (room) {
                log.debug("外卖送到没? [{}]", hasTakeout);
                if (!hasTakeout) {
                    log.debug("没外卖, 先歇会!");
                    try {
                        room.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("外卖送到没? [{}]", hasTakeout);
                if (hasTakeout) {
                    log.debug("可以开始干活了");
                } else {
                    log.debug("没干成活....");
                }
            }
        }, "小女").start();

        Thread.sleep(1000);
        new Thread(() -> {
            synchronized (room) {
                hasTakeout = true;
                log.debug("外卖到了");
                room.notifyAll();
            }
        }, "送外卖的").start();
    }
}
